home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / mach / amiga / scsi9091.lzh / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-24  |  12.9 KB  |  450 lines

  1. #include <exec/types.h>
  2. #include <exec/nodes.h>
  3. #include <exec/resident.h>
  4. #include <exec/errors.h>
  5. #include <libraries/expansionbase.h>
  6. #include <libraries/configvars.h>
  7. #include <devices/trackdisk.h>
  8.   
  9. /*
  10.  * Set SysBase to a local variable, that loads directly from 4 when it
  11.  * has to be reloaded
  12.  */
  13. #define BASE_EXT_DECL
  14. #define BASE_NAME (*(void **)4)
  15. #include <inline/exec.h>
  16. #include <inline/expansion.h>
  17.   
  18. #include "device.h"
  19.  
  20. /*
  21.  * in this file you find those device-commands, that are actually 
  22.  * implemented for this device. For commands, that just return true or
  23.  * some constant look in device.c.
  24.  */
  25.   
  26. extern int  lookup_cache (struct scsi_unit *su, ulong block_num, ubyte *buf);
  27. extern void update_cache (struct scsi_unit *su, long block_num, ubyte *buf);
  28. extern void invalidate_cache (struct scsi_unit *su);
  29. extern int AutoAutoRequest(char *l1, char *l2, char *l3, char *left, char *right);
  30.  
  31. DECL_DPRINTF;
  32.  
  33. #ifdef DEBUG
  34. #define FLASH_SCREEN() { int i; for (i=0; i < 10000; i++) *(unsigned short*)0xdff180=i;}
  35. #else
  36. #define FLASH_SCREEN()
  37. #endif
  38.  
  39. int
  40. scsi_read(struct IOStdReq *io_req)
  41. {
  42.   struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
  43.   struct SCSICmd *sc;
  44.   ulong length, this_length, this_offset, max_inc, data, type;
  45.   
  46. DPRINTF(("read: unit %ld, type $%lx, offset %ld, length %ld", 
  47.      su->scu_unitnum, su->scu_type, io_req->io_Offset, io_req->io_Length));
  48.   
  49.   length = io_req->io_Length;
  50.   data = (ulong) io_req->io_Data;
  51.   
  52. #ifdef ENABLE_CACHE
  53.   if (length == UNIT_SEC_SIZE)
  54.     {
  55.       if (lookup_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte *)data))
  56.     {
  57.       io_req->io_Actual = length;
  58.       return 0;
  59.     }
  60.     }
  61. #endif
  62.   
  63.   /*
  64.    * if the buffer is not word aligned, I have to use the unit buffer
  65.    * and later copy the bits and bytes, argl.. 
  66.    */
  67.   if (data & 1) 
  68.     {
  69.       data = (ulong) su->scu_buf;
  70.       max_inc = sizeof(su->scu_buf); /* *has* to be <= DMA_MAX_TRANSFER */
  71.     }
  72.   else
  73.     {
  74.       /* 2090-DMA circuit can only handle up to 64K direct DMA, sigh.. */
  75.       max_inc = DMA_MAX_TRANSFER;
  76.     }
  77.   
  78.   this_length = length > max_inc ? max_inc : length;
  79.   this_offset = io_req->io_Offset;
  80.   
  81.   /* don't care whether the medium is removable or not.. (yet:-)) */
  82.   type = su->scu_type & ~SCU_TYPE_RMB;
  83.   
  84.   if (type != SCU_TYPE_DIRECT && type != SCU_TYPE_SEQUENTIAL)
  85.     /* don't know how to access cd-roms, printers etc... */
  86.     return IOERR_NOCMD;
  87.   
  88.   sc = &su->scu_scsicmd;
  89.   sc->scsi_Flags = SCSIF_READ;
  90.   
  91.   /*
  92.    * if type is sequential, AND offset is 0, then we issue a REWIND
  93.    * before we start 
  94.    */
  95.   if (type == SCU_TYPE_SEQUENTIAL && this_offset == 0)
  96.     {
  97.       ubyte *cb = su->scu_cmd;
  98.       *cb++ = 1; /* REWIND */
  99.       *cb++ = 0; /* wait for completion */
  100.       *cb++ = 0;
  101.       *cb++ = 0;
  102.       *cb++ = 0;
  103.       *cb   = 0;
  104.       su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
  105.       sc->scsi_Length = 0;
  106.       PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  107.         (struct Message *)&su->scu_hmessage);
  108.     }
  109.   
  110.   io_req->io_Actual = 0;
  111.  
  112.   /* 
  113.    * this statement moved after REWIND to allow for READs with length 0
  114.    * to rewind the tape 
  115.    */
  116.   if (!length)
  117.     {
  118.       /* just abort right here.. it could be hazardrous to the DMA
  119.        * circuit if it had to transfer 0 byte .. */
  120.       return 0;
  121.     }
  122.   
  123.   do
  124.     {
  125.       if (type == SCU_TYPE_DIRECT)
  126.         {
  127.           ubyte *cb = su->scu_cmd;
  128.           *cb++ = 0x28;
  129.           *cb++ = 0;
  130.       *cb++ = 0; /* 24 + 9 exceeds 32 bit.. */
  131.       *cb++ = this_offset >> (16 + 9); /* heavy stuff for the */
  132.       *cb++ = this_offset >> ( 8 + 9); /* optimizer... :-))) */
  133.       *cb++ = this_offset >> (     9);
  134.           *cb++ = 0;
  135.           *cb++ = this_length >> ( 8 + 9);
  136.           *cb++ = this_length >> (     9);
  137.           *cb   = 0;
  138.         }
  139.       else /* SCU_TYPE_SEQUENTIAL */
  140.         {
  141.           ubyte *cb = su->scu_cmd;
  142.           *cb++ = 0x8; /* no extended read for seq devices */
  143.       *cb++ = 1;   /* use fixed size blocks */
  144.       *cb++ = this_length >> (16 + 9);
  145.       *cb++ = this_length >> ( 8 + 9);
  146.           *cb++ = this_length >> (     9);
  147.           *cb   = 0;
  148.         }
  149.       su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
  150.       sc->scsi_Data = (UWORD *)data;
  151.       sc->scsi_Length = this_length;
  152.       PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  153.         (struct Message *)&su->scu_hmessage);
  154.       
  155.       /* error check */
  156.       if (su->scu_hmessage.scm_cmd != 0)
  157.     {
  158.        /* better not retry sequ accesses.. */
  159.       if (type == SCU_TYPE_SEQUENTIAL)
  160.         return su->scu_hmessage.scm_cmd;
  161.       
  162.       if (su->scu_errors++ > UNIT_MAX_ERRORS)
  163.         {
  164.           sprintf(su->scu_buf, "Unit %d had %d errors",
  165.               su->scu_unitnum,
  166.               su->scu_errors + UNIT_MAX_ERRORS*su->scu_errorlevel);
  167.           
  168.           su->scu_errors = 0;
  169.           switch (su->scu_errorlevel ++)
  170.         {
  171.         case 0:  AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  172.                      "Please safe your data!",
  173.                      "Cancel", "Cancel");
  174.           break;
  175.         case 1:  AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  176.                      "Please don't use this unit anymore!",
  177.                      "I won't!", "I won't!");
  178.           break;
  179.         default: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  180.                      "You'd better use FORMAT anyway!",
  181.                      "Yes dad!", "Yes dad!");
  182.           break;
  183.         }
  184.           return su->scu_hmessage.scm_cmd;
  185.         }
  186.       continue; /* retry command */
  187.     }
  188.       /* do we have to copy (shudder, performance killer...) ?? */
  189.       if (data == (ulong) su->scu_buf)
  190.     /* I'm not allowed to directly increment the io_req pointer */
  191.     CopyMem((char *)data, (char*)io_req->io_Data+io_req->io_Actual, 
  192.         this_length);
  193.       else
  194.     data += this_length;
  195.       
  196.       io_req->io_Actual += sc->scsi_Actual;
  197.       length -= this_length;
  198.       this_offset += this_length;
  199.       
  200.       this_length = length > max_inc ? max_inc : length;
  201.       /*
  202.        * if scsi_Actual is 0, and there is no error, I can't imagine
  203.        * what's happening .. to prevent an infinite loop, I'll break
  204.        * and the application should take care of this strange device.. 
  205.        */
  206.     } while (this_length && sc->scsi_Actual);
  207.   
  208. #ifdef ENABLE_CACHE
  209.   if (io_req->io_Length == UNIT_SEC_SIZE)
  210.     update_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte*)io_req->io_Data);
  211. #endif
  212.   
  213.   return 0; /* if we get here, no errors happened.. */
  214. }
  215.  
  216. int
  217. scsi_write(struct IOStdReq *io_req)
  218. {
  219.   struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
  220.   struct SCSICmd *sc;
  221.   ulong length, this_length, this_offset, max_inc, data, type;
  222.   
  223. DPRINTF(("write: unit %ld, type $%lx, offset %ld, length %ld", 
  224.      su->scu_unitnum, su->scu_type, io_req->io_Offset, io_req->io_Length));
  225.   
  226.   length = io_req->io_Length;
  227.   data = (ulong) io_req->io_Data;
  228.   
  229.   if (!length)
  230.     {
  231.       /*
  232.        * just abort right here.. it could be hazardrous to the DMA
  233.        * circuit if it had to transfer 0 byte .. 
  234.        */
  235.       io_req->io_Actual = 0;
  236.       return 0;
  237.     }
  238.   
  239.   /*
  240.    * if the buffer is not word aligned, I have to use the unit buffer
  241.    * and copy the bits and bytes before the transfer, argl.. 
  242.    */
  243.   if (data & 1) 
  244.     {
  245.       data = (ulong) su->scu_buf;
  246.       max_inc = sizeof(su->scu_buf); /* *has* to be <= DMA_MAX_TRANSFER */
  247.     }
  248.   else
  249.     {
  250.       /* 2090-DMA circuit can only handle up to 64K direct DMA, sigh.. */
  251.       max_inc = DMA_MAX_TRANSFER;
  252.     }
  253.   
  254.   this_length = length > max_inc ? max_inc : length;
  255.   this_offset = io_req->io_Offset;
  256.   
  257.   /*
  258.    * do this check before performing any actions.. if something goes
  259.    * wrong, we end up with an invalidated cache, that's lots better
  260.    * than pretending it's still ok.. 
  261.    */
  262.   if (io_req->io_Length != UNIT_SEC_SIZE)
  263.     invalidate_cache (su);
  264.   
  265.   /* don't care whether the medium is removable or not.. (yet:-)) */
  266.   type = su->scu_type & ~SCU_TYPE_RMB;
  267.   if (type != SCU_TYPE_DIRECT && type != SCU_TYPE_SEQUENTIAL)
  268.     /* don't know how to access cd-roms, printers etc... */
  269.     return IOERR_NOCMD;
  270.   
  271.   sc = &su->scu_scsicmd;
  272.   /* rewind is not a write or a read, stick to the safe option.. */
  273.   sc->scsi_Flags = SCSIF_READ;
  274.   
  275.   /* if type is sequential, AND offset is 0, then we issue a REWIND
  276.    * before we start */
  277.   if (type == SCU_TYPE_SEQUENTIAL && this_offset==0)
  278.     {
  279.       ubyte *cb = su->scu_cmd;
  280.       *cb++ = 1; /* REWIND */
  281.       *cb++ = 0; /* wait for completion */
  282.       *cb++ = 0;
  283.       *cb++ = 0;
  284.       *cb++ = 0;
  285.       *cb   = 0;
  286.       su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
  287.       sc->scsi_Length = 0;
  288.       PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  289.         (struct Message *)&su->scu_hmessage);
  290.     }
  291.   
  292.   io_req->io_Actual = 0;
  293.   
  294.   do
  295.     {
  296.       /* do we have to copy (shudder, performance killer...) ?? */
  297.       if (data == (ulong) su->scu_buf)
  298.     /* I'm not allowed to directly increment the io_req pointer */
  299.     CopyMem((char*)io_req->io_Data+io_req->io_Actual,
  300.         (char*)data, this_length);
  301.       
  302.       if (type == SCU_TYPE_DIRECT)
  303.         {
  304.           ubyte *cb = su->scu_cmd;
  305.           *cb++ = 0x2a;
  306.           *cb++ = 0;
  307.       *cb++ = 0; /* 24 + 9 exceeds 32 bit.. */
  308.       *cb++ = this_offset >> (16 + 9); /* heavy stuff for the */
  309.       *cb++ = this_offset >> ( 8 + 9); /* optimizer... :-))) */
  310.       *cb++ = this_offset >> (     9);
  311.           *cb++ = 0;
  312.           *cb++ = this_length >> ( 8 + 9);
  313.           *cb++ = this_length >> (     9);
  314.           *cb   = 0;
  315.         }
  316.       else /* SCU_TYPE_SEQUENTIAL */
  317.         {
  318.           ubyte *cb = su->scu_cmd;
  319.           *cb++ = 0xa; /* no extended write for seq devices */
  320.       *cb++ = 1;   /* use fixed size blocks */
  321.       *cb++ = this_length >> (16 + 9);
  322.       *cb++ = this_length >> ( 8 + 9);
  323.           *cb++ = this_length >> (     9);
  324.           *cb   = 0;
  325.         }
  326.       su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
  327.       sc->scsi_Data = (UWORD *)data;
  328.       sc->scsi_Length = this_length;
  329.       sc->scsi_Flags = SCSIF_WRITE;
  330.       PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  331.         (struct Message *)&su->scu_hmessage);
  332.       
  333.       /* error check */
  334.       if (su->scu_hmessage.scm_cmd != 0)
  335.     {
  336.        /* better not retry sequ accesses.. */
  337.       if (type == SCU_TYPE_SEQUENTIAL)
  338.         return su->scu_hmessage.scm_cmd;
  339.       
  340.       if (su->scu_errors++ > UNIT_MAX_ERRORS)
  341.         {
  342.           sprintf(su->scu_buf, "Unit %d had %d errors",
  343.               su->scu_unitnum,
  344.               su->scu_errors + UNIT_MAX_ERRORS*su->scu_errorlevel);
  345.           
  346.           su->scu_errors = 0;
  347.           switch (su->scu_errorlevel ++)
  348.         {
  349.         case 0:  AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  350.                      "Please safe your data!",
  351.                      "Cancel", "Cancel");
  352.           break;
  353.         case 1:  AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  354.                      "Please don't use this unit anymore!",
  355.                      "I won't!", "I won't!");
  356.           break;
  357.         default: AutoAutoRequest(SCSI_NAME, (char *)su->scu_buf,
  358.                      "You'd better use FORMAT anyway!",
  359.                      "Yes dad!", "Yes dad!");
  360.           break;
  361.         }
  362.           return su->scu_hmessage.scm_cmd;
  363.         }
  364.       continue; /* retry command */
  365.     }
  366.       
  367.       if (data != (ulong) su->scu_buf)
  368.     data += this_length;
  369.       
  370.       io_req->io_Actual += sc->scsi_Actual;
  371.       length -= this_length;
  372.       this_offset += this_length;
  373.       
  374.       this_length = length > max_inc ? max_inc : length;
  375.       /*
  376.        * if scsi_Actual is 0, and there is no error, I can't imagine
  377.        * what's happening .. to prevent an infinite loop, I'll break
  378.        * and the application should take care of this strange device.. 
  379.        */
  380.     } while (this_length && sc->scsi_Actual);
  381.   
  382. #ifdef ENABLE_CACHE
  383.   if (io_req->io_Length == UNIT_SEC_SIZE)
  384.     update_cache (su, io_req->io_Offset / UNIT_SEC_SIZE, (ubyte*)io_req->io_Data);
  385. #endif
  386.   
  387.   return 0; /* if we get here, no errors happened.. */
  388. }
  389.  
  390. int
  391. scsi_format(struct IOStdReq *io_req)
  392. {
  393.   /*
  394.    * "could" do some checking, whether the parameters meet certain
  395.    * tougher criteria than for write, but who cares, my write can
  396.    * even cope with odd-aligned data, so what ? 
  397.    */
  398.   return scsi_write(io_req);
  399. }
  400.  
  401. /*
  402.  * this is one of the easiest commands of the whole device... the entire
  403.  * device structure is laid out for this to be implemented as good as
  404.  * possible:-))
  405.  */
  406. int
  407. scsi_direct(struct IOStdReq *io_req)
  408. {
  409.   struct scsi_msg sm;
  410.   struct scsi_unit *su;
  411.   
  412.   su = (struct scsi_unit *)io_req->io_Unit;
  413.   sm.scm_cmd = SCM_CMD_EXEC_SCSI;
  414.   sm.scm_unit = su->scu_unitnum;
  415.   sm.scm_message.mn_ReplyPort = &su->scu_unit.unit_MsgPort;
  416.   sm.scm_scsi_cmd = (struct SCSICmd *)io_req->io_Data;
  417.   
  418.   PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  419.         (struct Message *)&sm);
  420. DPRINTF(("scsi-direct: unit %ld, result %ld", su->scu_unitnum, sm.scm_cmd));
  421.   return sm.scm_cmd;
  422. }
  423.  
  424. int
  425. scsi_protstatus(struct IOStdReq *io_req)
  426. {
  427.   struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
  428.   struct SCSICmd *sc;
  429.   ulong  sense_buf;
  430.   ubyte *cb;
  431.   
  432.   sc = &su->scu_scsicmd;
  433.   sc->scsi_Flags = SCSIF_READ;
  434.   cb = su->scu_cmd;
  435.   *cb++ = 0x1A; /* MODE SENSE */
  436.   *cb++ = *cb++ = *cb++ = 0;
  437.   *cb++ = 4; /* allocated length */
  438.   *cb   = 0;
  439.   
  440.   su->scu_hmessage.scm_cmd = SCM_CMD_EXEC_SCSI;
  441.   sense_buf = 0;
  442.   sc->scsi_Data = (UWORD *)&sense_buf;
  443.   sc->scsi_Length = 4;
  444.   PutGetMsg(su->scu_hmsgport, &su->scu_unit.unit_MsgPort,
  445.         (struct Message *)&su->scu_hmessage);
  446.   
  447.   io_req->io_Actual = sense_buf & 0x00008000 ? 1 : 0; /* WP bit */
  448.   return su->scu_hmessage.scm_cmd;
  449. }
  450.